/*
	This file is part of Vajolet.

    Vajolet is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Vajolet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Vajolet.  If not, see <http://www.gnu.org/licenses/>
*/
#ifdef _WIN32
//#include <intrin.h>
//#include <xmmintrin.h>
#include <smmintrin.h>
#endif
#include <iostream>
#include "vajolet.h"
#include "data.h"
#include "bitops.h"

unsigned int (*bitCnt)(bitMap bitmap);
inline unsigned int swbitCnt(bitMap bitmap)
{
/*#ifdef _WIN32
	return __popcnt((unsigned int)bitmap)+__popcnt(bitmap>>32);
#else*/
	int n=0;
	while(bitmap){
		n++;
		bitmap &= bitmap - 1; // reset LS1B

	}
	return n;
//#endif
};

inline unsigned int hwbitCnt(bitMap bitmap)
{

	return __builtin_popcountl((unsigned int)bitmap)+__builtin_popcountl(bitmap>>32);
	return 0;
};

void displayBitmap(bitMap in, char viewRotated)
{
	int i, rank, file;
	char boardc[64];
 
	for (i = 0 ; i < 64 ; i++)
	{
		if (in & BITSET[i]) boardc[i] = '1';
		else boardc[i] = '.';
	}
 
	std::cout << std::endl << "as binary integer:" << std::endl;
      
	for (i = 63 ; i >= 0 ; i--)  std::cout << boardc[i];
	std::cout << std::endl << "  firstOne = " << firstOne(in) << ", lastOne = " << lastOne(in) << ", bitCnt = " << bitCnt(in) << std::endl;
	std::cout << std::endl << std::endl;
 
	if (viewRotated)
	{
		std::cout << "   hgfedcba" << std::endl << std::endl;
		for (rank = 0 ; rank <= 7; rank++)
		{
		std::cout << "   ";
		for (file = 7 ; file >= 0; file--)
		{
			std::cout << boardc[BOARDINDEX[file][rank]];
		}
		std::cout << " " << rank +1 << std::endl;
		}
	}
	else
	{
		for (rank = 7 ; rank >= 0; rank--)
		{
			std::cout << " " << rank +1<< " ";
			for (file = 0 ; file <= 7; file++)
			{
				std::cout << boardc[BOARDINDEX[file][rank]];
			}
			std::cout << std::endl;
		}
		std::cout << std::endl << "   abcdefgh" << std::endl;
	}
	std::cout << std::endl;
	return;
}

unsigned int firstOne(bitMap bitmap)
{
#ifdef _WIN32
	unsigned long res;
	if((res=__builtin_ffsl((unsigned long) bitmap))!=0){
		return res-1;
	}
	else{
		res=__builtin_ffsl(bitmap>>32);
		return res+31;
		
	}
#else
	
	// De Bruijn Multiplication, see http://chessprogramming.wikispaces.com/BitScan
	// don't use this if bitmap = 0
 
	static const int INDEX64[64] = {
	63,  0, 58,  1, 59, 47, 53,  2,
	60, 39, 48, 27, 54, 33, 42,  3,
	61, 51, 37, 40, 49, 18, 28, 20,
	55, 30, 34, 11, 43, 14, 22,  4,
	62, 57, 46, 52, 38, 26, 32, 41,
	50, 36, 17, 19, 29, 10, 13, 21,
	56, 45, 25, 31, 35, 16,  9, 12,
	44, 24, 15,  8, 23,  7,  6,  5  };
 
	static const U64 DEBRUIJN64 = U64(0x07EDD5E59A4E28C2);
 
	// here you would get a warming: "unary minus operator applied to unsigned type",
	// that's intended and OK so I'll disable it
#pragma warning (disable: 4146)
	return INDEX64[((bitmap & -bitmap) * DEBRUIJN64) >> 58]; 
#endif
}

unsigned int lastOne(bitMap bitmap)
{
#ifdef _WIN323
	unsigned long res;
	if(_BitScanReverse(&res,bitmap>>32)!=0){
		return res+32;
	}
	else{
		_BitScanReverse(&res,(unsigned long)bitmap);
		return res;
		
	}
#else
	// this is Eugene Nalimov's bitScanReverse
	// use firstOne if you can, it is faster than lastOne.
	// don't use this if bitmap = 0
	
	int result = 0;
	if (bitmap > 0xFFFFFFFF)
	{
		bitmap >>= 32;
		result = 32;
	}
	if (bitmap > 0xFFFF)
	{
		bitmap >>= 16;
		result += 16;
	}
	if (bitmap > 0xFF)
	{
		bitmap >>= 8;
		result += 8;
	}
	return result + MS1BTABLE[bitmap];
#endif
}

void checkCpuCapabilities(void){
	//int CPUInfo[4];
	//__cpuid(CPUInfo,1);
	bitCnt=&swbitCnt;
	//if(CPUInfo[3]& (1ULL<<23)){
		bitCnt=&hwbitCnt;
	//}
}
